defmodule Iocp.Worker do
  @moduledoc false

  use GenServer, restart: :temporary

  def start_link({client, device_address}) do
    GenServer.start_link(__MODULE__, {client, device_address})
  end

  @impl true
  def init({client, device_address}) do
    GenServer.cast(self(), :serve)
    {:ok, {client, device_address}}
  end

  @impl true
  def handle_cast(:serve, {client, device_address}) do
    start_receive_loop(client, device_address)
    periodical(:adjust_time, client, device_address)
    periodical(:fetch_data, client, device_address)
    {:noreply, {client, device_address}}
  end

  @impl true
  def handle_info({:schedule, work}, {client, device_address}) do
    periodical(work, client, device_address)
    {:noreply, {client, device_address}}
  end

  def handle_info(_, state) do
    {:noreply, state}
  end

  defp start_receive_loop(client, device_address) do
    spawn_link(fn -> Iocp.Receiver.receive(client, device_address) end)
  end

  @task_intervals [
    adjust_time: 86400_000,
    fetch_data: 60_000
  ]
  for {task, interval} <- @task_intervals do
    defp periodical(unquote(task), client, device_address) do
      spawn_link(fn -> unquote(task)(client, device_address) end)
      schedule(unquote(task), unquote(interval))
    end
  end

  defp schedule(task, next_start) do
    Process.send_after(self(), {:schedule, task}, next_start)
  end

  defp adjust_time(client, device_address) do
    Iocp.Sender.send_adjust_time(client, device_address)
  end

  defp fetch_data(client, device_address) do
    Iocp.Sender.send_fetch_data(client, device_address)
  end

end
